#include <cpp/crt.h>
#include <rtos/thread.h>
#include <bsp.h>
#include <cmsis_os.h>
#include <core.h>
#include <sheriffos.h>

namespace user_init {
InitFnType const __init_pre_core__front __attribute__((used, section(".sheriff_init_fn.10.start"))) = {nullptr};
InitFnType const __init_pre_core__back __attribute__((used, section(".sheriff_init_fn.19.end"))) = {nullptr};

void initPreCore() {
    for (auto* fn = (&__init_pre_core__front) + 1; fn < (&__init_pre_core__back); fn++) {
        if (fn->entry != nullptr) {
            fn->entry();
        }
    }
}

InitFnType const __init_post_core__front __attribute__((used, section(".sheriff_init_fn.20.start"))) = {nullptr};
InitFnType const __init_pre_env__back __attribute__((used, section(".sheriff_init_fn.39.end"))) = {nullptr};

void initPostCore() {
    for (auto* fn = (&__init_post_core__front) + 1; fn < (&__init_pre_env__back); fn++) {
        if (fn->entry != nullptr) {
            fn->entry();
        }
    }
}

InitFnType const __init_env__front __attribute__((used, section(".sheriff_init_fn.40.start"))) = {nullptr};
InitFnType const __init_pre_device__back __attribute__((used, section(".sheriff_init_fn.69.end"))) = {nullptr};

void initEnv() {
    for (auto* fn = (&__init_env__front) + 1; fn < (&__init_pre_device__back); fn++) {
        if (fn->entry != nullptr) {
            fn->entry();
        }
    }
}

InitFnType const __init_device__front __attribute__((used, section(".sheriff_init_fn.70.start"))) = {nullptr};
InitFnType const __init_late__back __attribute__((used, section(".sheriff_init_fn.99.end"))) = {nullptr};

void initDevice() {
    for (auto* fn = (&__init_device__front) + 1; fn < (&__init_late__back); fn++) {
        if (fn->entry != nullptr) {
            fn->entry();
        }
    }
}
}  // namespace user_init

namespace os {
extern TaskLists* taskLists_head;
}  // namespace os

namespace {
TaskHandle_t hDefaultTask = nullptr;
uint32_t defaultTaskStack[512];  // 任务堆栈
StaticTask_t defaultTaskTCB;

[[noreturn]] void defaultTask(void const* param) {
    (void)param;

    user_init::initPostCore();

    /* Restore the time base of the HAL library after the kernel is turned on  */
    HAL_ResumeTick();

    bsp::Init();

    // 硬件定时器
#if BSP_HAS_HARD_TIMER == 1
    os::HardTimer::Init();
#endif

    /* Init SEGGER RTT and PrintfMutex */
    // bsp::IOinit();

#if SHERIFF_OS_ENABLE_SHELL == 1 and BSP_HAS_SHELL == 1
    bsp::ShellInit();
#endif

    user_init::initEnv();

    // 构造函数调用
    CXX_GlobalInit();

    user_init::initDevice();
    // 启动全部线程
    for (; os::taskLists_head != nullptr; os::taskLists_head = os::taskLists_head->next)
        vTaskResume(os::taskLists_head->ptr);

    for (;;) {
        bsp::updateGlobalTick();

        osDelay(1);
    }
}
}  // namespace

bool isSchedulerStart = false;

[[noreturn]] int main() {
    user_init::initPreCore();
    // 初始化hal库
    HAL_Init();
    // 初始化时钟
    bsp::clockInit();

    // 开启默认线程
    hDefaultTask =
        xTaskCreateStatic(reinterpret_cast<TaskFunction_t>(defaultTask), "defaultTask", sizeof(defaultTaskStack) / 4,
                          nullptr, configMAX_PRIORITIES - 1, defaultTaskStack, &defaultTaskTCB);

    // 开启调度器
    isSchedulerStart = true;
    /* Close the HAL library time base before kernel startup */
    HAL_SuspendTick();
    vTaskStartScheduler();

    for (;;) {
    }
}

// ------ OS error handler ------
[[noreturn]] __attribute__((weak)) void osError([[maybe_unused]] char const* err) {
    __disable_irq();
#if SHERIFF_OS_ENABLE_SHELL == 1 and BSP_HAS_SHELL == 1
    // logError("%s", err);
#endif
    while (true) {
    }
}

// ------ Override time base for HAL ------
extern "C" {
// ---- HAL_Delay
void HAL_Delay(uint32_t const Delay) { bsp::delay_ms(Delay); }

// ---- HAL_GetTick
uint32_t HAL_GetTick(void) {
    static uint32_t ticks = 0U;
    uint32_t i;

    if (isSchedulerStart) {
        return xTaskGetTickCount();
    }

    // Before threadX start
    for (i = (SystemCoreClock >> 14U); i > 0U; i--) {
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
        __NOP();
    }

    return ++ticks;
}
}